<template>
  <div class="data-visualization">
    <div class="canvas" :style="{ opacity: 0.2 }">
      <!-- 背景 canvas 已转换为 div -->
      <div class="background-container"></div>
    </div>
    
    <div class="head">
      <h1>电商平台数据大屏</h1>
      <div class="weather">
        <span>{{ currentTime }}</span>
        <el-button 
          type="primary" 
          size="small" 
          :loading="loading"
          @click="handleRefresh"
          class="refresh-btn"
        >
          刷新数据
        </el-button>
        <!-- 添加全屏按钮 -->
        <el-button
          type="success"
          size="small"
          @click="toggleFullscreen"
          class="fullscreen-btn"
        >
          <i :class="isFullscreen ? 'el-icon-close' : 'el-icon-full-screen'"></i>
          {{ isFullscreen ? '退出全屏' : '全屏显示' }}
        </el-button>
      </div>
    </div>

    <!-- 添加商家入驻跑马灯 -->
    <div class="marquee-container">
      <div class="marquee-icon">
        <i class="el-icon-shop"></i>
      </div>
      <div class="marquee-content">
        <ul class="marquee-list" :style="{ transform: `translateX(-${marqueeOffset}px)` }">
          <li v-for="(item, index) in merchantNews" :key="index">
            <span class="merchant-name">{{ item.name }}</span>
            <span class="merchant-time">{{ item.time }}</span>
            <span class="merchant-location">{{ item.location }}</span>
          </li>
        </ul>
      </div>
    </div>

    <div class="mainbox">
      <el-alert
        v-if="error"
        :title="error"
        type="error"
        show-icon
        closable
        @close="clearError"
        class="error-alert"
      />
      
      <!-- 添加预加载进度显示 -->
      <div v-if="preloadProgress && preloadProgress.total > 0" class="preload-progress">
        <div class="progress-header">
          <div class="progress-title">
            <i class="el-icon-loading"></i>
            <span>数据预加载中...</span>
          </div>
          <el-button 
            type="danger" 
            size="small" 
            @click="cancelPreload"
            :disabled="preloadProgress.status === 'success'"
          >
            取消预加载
          </el-button>
        </div>
        <div class="progress-info">
          <span>当前进度：{{ preloadProgress.current }}/{{ preloadProgress.total }}</span>
          <span>预计剩余时间：{{ formatTime(preloadProgress.estimatedTime) }}</span>
        </div>
        <el-progress 
          :percentage="(preloadProgress.current / preloadProgress.total) * 100"
          :status="preloadProgress.status"
          :stroke-width="4"
          :show-text="false"
          class="progress-bar"
        />
        <div class="progress-details" v-if="preloadProgress.currentItem">
          <div class="current-item">
            <span>正在加载：</span>
            <span class="item-name">{{ preloadProgress.currentItem }}</span>
          </div>
          <div class="item-status" :class="preloadProgress.currentItemStatus">
            {{ getStatusText(preloadProgress.currentItemStatus) }}
          </div>
        </div>
      </div>
      
      <ul class="clearfix">
        <li>
          <div class="boxall" style="height: 3.2rem">
            <div class="alltitle">交易统计</div>
            <div class="extra-wrapper" slot="tabBarExtraContent">
              <j-dict-select-tag 
                type="radioButton" 
                v-model="dateTypeVal.trade" 
                dictCode="vueDateType" 
                :trigger-change="true"
                @change="(e)=> handleDateTypeChange(methodType.trade, e)"
                style="margin-right: 20px;"
              />
              <a-date-picker 
                v-if="dateTypeVal.trade === 'day'" 
                :showToday="false" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.trade, dateString)"
              />
              <a-month-picker 
                v-if="dateTypeVal.trade === 'month'" 
                placeholder="请选择月份" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.trade, dateString)"
              />
            </div>
            <div class="allnav" ref="echart1">
              <div v-if="loading" class="loading-mask">
                <i class="el-icon-loading"></i>
              </div>
            </div>
            <div class="boxfoot"></div>
          </div>
          <div class="boxall" style="height: 3.2rem">
            <div class="alltitle">会员统计</div>
            <div class="extra-wrapper" slot="tabBarExtraContent">
              <j-dict-select-tag 
                type="radioButton" 
                v-model="dateTypeVal.member" 
                dictCode="vueDateType" 
                :trigger-change="true"
                @change="(e)=> handleDateTypeChange(methodType.member, e)"
                style="margin-right: 20px;"
              />
              <a-date-picker 
                v-if="dateTypeVal.member === 'day'" 
                :showToday="false" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.member, dateString)"
              />
              <a-month-picker 
                v-if="dateTypeVal.member === 'month'" 
                placeholder="请选择月份" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.member, dateString)"
              />
            </div>
            <div class="allnav" ref="echart2">
              <div v-if="loading" class="loading-mask">
                <i class="el-icon-loading"></i>
              </div>
            </div>
            <div class="boxfoot"></div>
          </div>
          <div class="boxall" style="height: 3.2rem">
            <div class="alltitle">快捷统计</div>
            <div style="height:100%; width: 100%;">
              <div class="sy" ref="fb1">
                <div v-if="loading" class="loading-mask">
                  <i class="el-icon-loading"></i>
                </div>
              </div>
              <div class="sy" ref="fb2">
                <div v-if="loading" class="loading-mask">
                  <i class="el-icon-loading"></i>
                </div>
              </div>
              <div class="sy" ref="fb3">
                <div v-if="loading" class="loading-mask">
                  <i class="el-icon-loading"></i>
                </div>
              </div>
            </div>
          </div>
          
          <!-- 添加商家地区渗透率 -->
          <div class="boxall" style="height: 3.2rem">
            <div class="alltitle">商家地区渗透率</div>
            <div class="allnav" ref="echart7">
              <div v-if="loading" class="loading-mask">
                <i class="el-icon-loading"></i>
              </div>
            </div>
            <div class="boxfoot"></div>
          </div>

          <!-- 添加用户地区渗透率 -->
          <div class="boxall" style="height: 3.2rem">
            <div class="alltitle">用户地区渗透率</div>
            <div class="allnav" ref="echart8">
              <div v-if="loading" class="loading-mask">
                <i class="el-icon-loading"></i>
              </div>
            </div>
            <div class="boxfoot"></div>
          </div>
        </li>
        <li>
          <div class="bar">
            <div class="barbox">
              <ul class="clearfix">
                <li class="pulll_left counter">{{ totalIncome }}</li>
                <li class="pulll_left counter">{{ totalExpense }}</li>
              </ul>
            </div>
            <div class="barbox2">
              <ul class="clearfix">
                <li class="pulll_left">年度总收入</li>
                <li class="pulll_left">年度总支出</li>
              </ul>
            </div>
          </div>
          <div class="map">
            <div class="map4" ref="map1"></div>
          </div>
        </li>
        <li>
          <div class="boxall" style="height:3.4rem">
            <div class="alltitle">商品统计</div>
            <div class="extra-wrapper" slot="tabBarExtraContent">
              <j-dict-select-tag 
                type="radioButton" 
                v-model="dateTypeVal.good" 
                dictCode="vueDateType" 
                :trigger-change="true"
                @change="(e)=> handleDateTypeChange(methodType.good, e)"
                style="margin-right: 20px;"
              />
              <a-date-picker 
                v-if="dateTypeVal.good === 'day'" 
                :showToday="false" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.good, dateString)"
              />
              <a-month-picker 
                v-if="dateTypeVal.good === 'month'" 
                placeholder="请选择月份" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.good, dateString)"
              />
            </div>
            <div class="allnav" ref="echart4"></div>
            <div class="boxfoot"></div>
          </div>
          <div class="boxall" style="height: 3.2rem">
            <div class="alltitle">订单统计</div>
            <div class="extra-wrapper" slot="tabBarExtraContent">
              <j-dict-select-tag 
                type="radioButton" 
                v-model="dateTypeVal.order" 
                dictCode="vueDateType" 
                :trigger-change="true"
                @change="(e)=> handleDateTypeChange(methodType.order, e)"
                style="margin-right: 20px;"
              />
              <a-date-picker 
                v-if="dateTypeVal.order === 'day'" 
                :showToday="false" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.order, dateString)"
              />
              <a-month-picker 
                v-if="dateTypeVal.order === 'month'" 
                placeholder="请选择月份" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.order, dateString)"
              />
            </div>
            <div class="allnav" ref="echart5"></div>
            <div class="boxfoot"></div>
          </div>
          <div class="boxall" style="height: 3rem">
            <div class="alltitle">优惠券统计</div>
            <div class="extra-wrapper" slot="tabBarExtraContent">
              <j-dict-select-tag 
                type="radioButton" 
                v-model="dateTypeVal.coupon" 
                dictCode="vueDateType" 
                :trigger-change="true"
                @change="(e)=> handleDateTypeChange(methodType.coupon, e)"
                style="margin-right: 20px;"
              />
              <a-date-picker 
                v-if="dateTypeVal.coupon === 'day'" 
                :showToday="false" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.coupon, dateString)"
              />
              <a-month-picker 
                v-if="dateTypeVal.coupon === 'month'" 
                placeholder="请选择月份" 
                :style="{width: '156px'}"
                @change="(date,dateString)=> requestInfo(methodType.coupon, dateString)"
              />
            </div>
            <div class="allnav" ref="echart6"></div>
            <div class="boxfoot"></div>
          </div>

          <!-- 添加商家收益排行 -->
          <div class="boxall" style="height: 3.2rem">
            <div class="alltitle">商家收益排行</div>
            <div class="allnav" ref="echart9">
              <div v-if="loading" class="loading-mask">
                <i class="el-icon-loading"></i>
              </div>
            </div>
            <div class="boxfoot"></div>
          </div>

          <!-- 添加消费者提现排行 -->
          <div class="boxall" style="height: 3.2rem">
            <div class="alltitle">消费者提现排行</div>
            <div class="allnav" ref="echart10">
              <div v-if="loading" class="loading-mask">
                <i class="el-icon-loading"></i>
              </div>
            </div>
            <div class="boxfoot"></div>
          </div>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import 'echarts/map/js/china'
import { Message } from 'element-ui'
import { cacheService } from './services/cacheService'
import {
  getTradeStatistics,
  getMemberStatistics,
  getRegionStatistics,
  getGoodStatistics,
  getOrderStatistics,
  getCouponStatistics,
  getQuickStatistics,
  getIncomeExpenseStatistics,
  clearStatisticsCache,
  preloadData,
  getCacheStatus,
  getMerchantNews,
  getMerchantPenetrationStatistics,
  getUserPenetrationStatistics,
  getMerchantRankingStatistics,
  getConsumerRankingStatistics
} from './services/statisticsService'
import { websocketService } from './services/websocketService'

export default {
  name: 'DataVisualization',
  data() {
    return {
      currentTime: '',
      totalIncome: 0,
      totalExpense: 0,
      loading: false,
      error: '',
      selectedRegion: '',
      currentTimeRange: 0,
      dateTypeVal: {
        trade: 'total',
        member: 'total',
        good: 'total',
        order: 'total',
        coupon: 'total'
      },
      methodType: {
        trade: 'trade',
        member: 'member',
        good: 'good',
        order: 'order',
        coupon: 'coupon'
      },
      cacheStatus: null,
      isFullscreen: false,
      preloadProgress: {
        current: 0,
        total: 0,
        status: '',
        currentItem: '',
        currentItemStatus: '',
        estimatedTime: 0,
        startTime: 0
      },
      merchantNews: [],
      marqueeOffset: 0,
      timer: null,
      dataTimer: null,
      preloadTimer: null,
      marqueeTimer: null,
      preloadController: null
    }
  },
  methods: {
    toggleFullscreen() {
      if (!this.isFullscreen) {
        // 进入全屏模式
        if (document.documentElement.requestFullscreen) {
          document.documentElement.requestFullscreen();
        } else if (document.documentElement.webkitRequestFullscreen) { /* Safari */
          document.documentElement.webkitRequestFullscreen();
        } else if (document.documentElement.msRequestFullscreen) { /* IE11 */
          document.documentElement.msRequestFullscreen();
        }
        this.isFullscreen = true;
      } else {
        // 退出全屏模式
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.webkitExitFullscreen) { /* Safari */
          document.webkitExitFullscreen();
        } else if (document.msExitFullscreen) { /* IE11 */
          document.msExitFullscreen();
        }
        this.isFullscreen = false;
      }
      
      // 调整图表大小以适应全屏变化
      setTimeout(() => {
        this.resizeCharts();
      }, 300);
    },
    
    handleFullscreenChange() {
      this.isFullscreen = !!document.fullscreenElement || 
                         !!document.webkitFullscreenElement || 
                         !!document.msFullscreenElement;
    },
    
    updateTime() {
      const dt = new Date()
      const y = dt.getFullYear()
      const mt = dt.getMonth() + 1
      const day = dt.getDate()
      const h = dt.getHours()
      const m = dt.getMinutes()
      const s = dt.getSeconds()
      this.currentTime = `${y}年${mt}月${day}-${h}时${m}分${s}秒`
    },
    clearError() {
      this.error = ''
    },
    async handleRefresh() {
      clearStatisticsCache()
      await this.fetchData()
    },
    updateCacheStatus() {
      this.cacheStatus = getCacheStatus()
    },
    formatTime(seconds) {
      if (seconds <= 0) return '计算中...'
      if (seconds < 60) return `${Math.ceil(seconds)}秒`
      const minutes = Math.ceil(seconds / 60)
      return `${minutes}分钟`
    },
    getStatusText(status) {
      switch (status) {
        case 'loading': return '加载中'
        case 'success': return '加载成功'
        case 'error': return '加载失败'
        default: return ''
      }
    },
    updatePreloadProgress(current, total, currentItem = '', status = 'loading') {
      const now = Date.now()
      
      // 添加安全检查
      if (!this.preloadProgress) {
        this.preloadProgress = {
          current: 0,
          total: 0,
          status: '',
          currentItem: '',
          currentItemStatus: '',
          estimatedTime: 0,
          startTime: now
        }
      }
      
      const elapsed = (now - this.preloadProgress.startTime) / 1000
      // 防止除以零错误
      const remaining = current > 0 ? (elapsed / current) * (total - current) : 0
      
      this.preloadProgress = {
        ...this.preloadProgress,
        current,
        total,
        currentItem,
        currentItemStatus: status,
        estimatedTime: remaining
      }

      if (current === total) {
        this.preloadProgress.status = 'success'
        Message.success('数据预加载完成')
      }
    },
    cancelPreload() {
      if (this.preloadController) {
        this.preloadController.abort()
        this.preloadProgress.status = 'exception'
        Message.warning('已取消数据预加载')
      }
    },
    async handlePreload() {
      if (this.preloadController) {
        console.warn('上一次预加载尚未完成，跳过本次预加载');
        return;
      }
      
      try {
        const preloadQueue = cacheService.getPreloadQueue();
        
        // 始终初始化preloadController
        this.preloadController = new AbortController();
        
        // 即使队列为空也初始化preloadProgress
        this.preloadProgress = {
          current: 0,
          total: preloadQueue.length,
          status: preloadQueue.length === 0 ? 'success' : '',
          currentItem: '',
          currentItemStatus: '',
          estimatedTime: 0,
          startTime: Date.now()
        };
        
        // 如果队列为空，直接返回
        if (preloadQueue.length === 0) {
          this.preloadController = null;
          return;
        }
        
        const processQueue = async () => {
          for (let index = 0; index < preloadQueue.length; index++) {
            // 检查是否已取消
            if (this.preloadController.signal.aborted) {
              throw new DOMException('预加载已取消', 'AbortError');
            }
            
            const key = preloadQueue[index];
            const [type, param] = key.split('_');
            
            try {
              this.updatePreloadProgress(index, preloadQueue.length, key, 'loading');
              
              // 添加超时处理
              const timeoutPromise = new Promise((_, reject) => {
                setTimeout(() => reject(new Error('请求超时')), 30000); // 30秒超时
              });
              
              const dataPromise = this.fetchDataByType(type, param, this.preloadController.signal);
              
              // 使用 Promise.race 实现超时处理
              const data = await Promise.race([dataPromise, timeoutPromise]);
              
              cacheService.set(key, data);
              cacheService.removeFromPreloadQueue(key);
              this.updatePreloadProgress(index + 1, preloadQueue.length, key, 'success');
            } catch (error) {
              if (error.name === 'AbortError') {
                throw error;
              }
              console.error(`预加载数据失败: ${key}`, error);
              this.updatePreloadProgress(index + 1, preloadQueue.length, key, 'error');
              // 继续处理下一个，不中断整个队列
            }
          }
        };

        await processQueue();
        this.updateCacheStatus();
      } catch (error) {
        if (error.name === 'AbortError') {
          console.log('预加载已被用户取消');
          return;
        }
        console.error('预加载数据失败:', error);
        Message.error('预加载数据失败');
        this.preloadProgress.status = 'exception';
      } finally {
        this.preloadController = null;
      }
    },
    async requestInfo(method, dateString) {
      this.loading = true
      try {
        let response
        switch(method) {
          case this.methodType.trade:
            response = await getTradeStatistics(dateString)
            if (this.$refs.echart1) this.updateChartData(this.$refs.echart1, 'trade', response)
            break
          case this.methodType.member:
            response = await getMemberStatistics(dateString)
            if (this.$refs.echart2) this.updateChartData(this.$refs.echart2, 'member', response)
            break
          case this.methodType.good:
            response = await getGoodStatistics(dateString)
            if (this.$refs.echart4) this.updateChartData(this.$refs.echart4, 'good', response)
            break
          case this.methodType.order:
            response = await getOrderStatistics(dateString)
            if (this.$refs.echart5) this.updateChartData(this.$refs.echart5, 'order', response)
            break
          case this.methodType.coupon:
            response = await getCouponStatistics(dateString)
            if (this.$refs.echart6) this.updateChartData(this.$refs.echart6, 'coupon', response)
            break
        }
        Message.success('数据更新成功')
      } catch (error) {
        console.error('获取数据失败:', error)
        Message.error('数据更新失败')
      } finally {
        this.loading = false
      }
    },
    handleDateTypeChange(method, e) {
      const type = e.target.value
      this.dateTypeVal[method] = type
      if (type === 'total' || type === 'today') {
        this.requestInfo(method, null)
      }
    },
    customDateChoice(method, range) {
      this.requestInfo(method, {
        start: range[0].format('YYYY-MM-DD'),
        end: range[1].format('YYYY-MM-DD')
      })
    },
    async fetchData() {
      this.loading = true;
      this.error = '';
      
      const fetchWithErrorHandling = async (operation, fn) => {
        try {
          return await fn();
        } catch (error) {
          console.error(`获取${operation}数据失败:`, error);
          // 不立即显示错误，而是继续尝试其他操作
          return null;
        }
      };
      
      // 记录失败的操作
      const failedOperations = [];
      
      try {
        // 获取各类统计数据
        const tradePromise = fetchWithErrorHandling('交易统计', () => this.requestInfo(this.methodType.trade, null));
        const memberPromise = fetchWithErrorHandling('会员统计', () => this.requestInfo(this.methodType.member, null));
        const goodPromise = fetchWithErrorHandling('商品统计', () => this.requestInfo(this.methodType.good, null));
        const orderPromise = fetchWithErrorHandling('订单统计', () => this.requestInfo(this.methodType.order, null));
        const couponPromise = fetchWithErrorHandling('优惠券统计', () => this.requestInfo(this.methodType.coupon, null));
        
        // 并行执行所有请求
        await Promise.all([tradePromise, memberPromise, goodPromise, orderPromise, couponPromise]);

        // 获取快捷统计
        const quickData = await fetchWithErrorHandling('快捷统计', async () => {
          const data = await getQuickStatistics();
          if (!data) throw new Error('获取快捷统计数据为空');
          return data;
        });
        
        if (quickData) {
          if (this.$refs.fb1) this.$refs.fb1.innerHTML = `<span>今日订单：${quickData.orderCount || 0}</span>`;
          if (this.$refs.fb2) this.$refs.fb2.innerHTML = `<span>今日会员：${quickData.memberCount || 0}</span>`;
          if (this.$refs.fb3) this.$refs.fb3.innerHTML = `<span>今日商品：${quickData.goodCount || 0}</span>`;
        } else {
          failedOperations.push('快捷统计');
        }

        // 获取收支统计
        const incomeExpenseData = await fetchWithErrorHandling('收支统计', async () => {
          const data = await getIncomeExpenseStatistics();
          if (!data) throw new Error('获取收支统计数据为空');
          return data;
        });
        
        if (incomeExpenseData) {
          this.totalIncome = incomeExpenseData.totalIncome || 0;
          this.totalExpense = incomeExpenseData.totalExpense || 0;
        } else {
          failedOperations.push('收支统计');
        }

        // 获取商家地区渗透率
        const merchantPenetrationData = await fetchWithErrorHandling('商家地区渗透率', async () => {
          const data = await getMerchantPenetrationStatistics();
          if (!data) throw new Error('获取商家地区渗透率数据为空');
          return data;
        });
        
        if (merchantPenetrationData && this.$refs.echart7) {
          this.updateChartData(this.$refs.echart7, 'merchant_penetration', merchantPenetrationData);
        } else if (!merchantPenetrationData) {
          failedOperations.push('商家地区渗透率');
        }

        // 获取用户地区渗透率
        const userPenetrationData = await fetchWithErrorHandling('用户地区渗透率', async () => {
          const data = await getUserPenetrationStatistics();
          if (!data) throw new Error('获取用户地区渗透率数据为空');
          return data;
        });
        
        if (userPenetrationData && this.$refs.echart8) {
          this.updateChartData(this.$refs.echart8, 'user_penetration', userPenetrationData);
        } else if (!userPenetrationData) {
          failedOperations.push('用户地区渗透率');
        }

        // 获取商家收益排行
        const merchantRankingData = await fetchWithErrorHandling('商家收益排行', async () => {
          const data = await getMerchantRankingStatistics();
          if (!data) throw new Error('获取商家收益排行数据为空');
          return data;
        });
        
        if (merchantRankingData && this.$refs.echart9) {
          this.updateChartData(this.$refs.echart9, 'merchant_ranking', merchantRankingData);
        } else if (!merchantRankingData) {
          failedOperations.push('商家收益排行');
        }

        // 获取消费者提现排行
        const consumerRankingData = await fetchWithErrorHandling('消费者提现排行', async () => {
          const data = await getConsumerRankingStatistics();
          if (!data) throw new Error('获取消费者提现排行数据为空');
          return data;
        });
        
        if (consumerRankingData && this.$refs.echart10) {
          this.updateChartData(this.$refs.echart10, 'consumer_ranking', consumerRankingData);
        } else if (!consumerRankingData) {
          failedOperations.push('消费者提现排行');
        }

        // 更新缓存状态
        this.updateCacheStatus();

        // 处理失败的操作
        if (failedOperations.length > 0) {
          this.error = `以下数据更新失败: ${failedOperations.join(', ')}，将在下次刷新时重试`;
          Message.warning(`部分数据(${failedOperations.join(', ')})更新失败，将在下次刷新时重试`);
        } else {
          Message.success('数据更新成功');
        }
      } catch (error) {
        console.error('获取数据失败:', error);
        this.error = '数据获取失败，请稍后重试';
        Message.error('数据更新失败');
      } finally {
        this.loading = false;
      }
    },
    async handleRegionSelect(data) {
      if (!data || !data.region) return;
      
      this.selectedRegion = data.region
      this.loading = true
      try {
        // 获取选中地区的详细数据
        const regionData = await getRegionStatistics(data.region)
        if (regionData && this.$refs.echart1) {
          this.updateChartData(this.$refs.echart1, 'trade', regionData.trade || { values: [] })
        }
        if (regionData && this.$refs.echart2) {
          this.updateChartData(this.$refs.echart2, 'member', regionData.member || { values: [] })
        }
        if (regionData && this.$refs.echart4) {
          this.updateChartData(this.$refs.echart4, 'good', regionData.good || { categories: [] })
        }
        if (regionData && this.$refs.echart5) {
          this.updateChartData(this.$refs.echart5, 'order', regionData.order || { values: [] })
        }
        if (regionData && this.$refs.echart6) {
          this.updateChartData(this.$refs.echart6, 'coupon', regionData.coupon || { values: [] })
        }
        
        Message.success(`已更新 ${data.region} 地区数据`)
      } catch (error) {
        console.error('获取地区数据失败:', error)
        Message.error('获取地区数据失败')
      } finally {
        this.loading = false
      }
    },
    async handleTimeRangeChange(data) {
      if (!data || !data.timeRange) return;
      
      this.currentTimeRange = data.timeRange
      this.loading = true
      try {
        // 根据时间范围获取数据
        const timeRangeData = await Promise.all([
          getTradeStatistics(data.timeRange),
          getMemberStatistics(data.timeRange),
          getGoodStatistics(data.timeRange),
          getOrderStatistics(data.timeRange),
          getCouponStatistics(data.timeRange)
        ])

        if (timeRangeData[0] && this.$refs.echart1) {
          this.updateChartData(this.$refs.echart1, 'trade', timeRangeData[0])
        }
        if (timeRangeData[1] && this.$refs.echart2) {
          this.updateChartData(this.$refs.echart2, 'member', timeRangeData[1])
        }
        if (timeRangeData[2] && this.$refs.echart4) {
          this.updateChartData(this.$refs.echart4, 'good', timeRangeData[2])
        }
        if (timeRangeData[3] && this.$refs.echart5) {
          this.updateChartData(this.$refs.echart5, 'order', timeRangeData[3])
        }
        if (timeRangeData[4] && this.$refs.echart6) {
          this.updateChartData(this.$refs.echart6, 'coupon', timeRangeData[4])
        }

        Message.success('已更新时间范围数据')
      } catch (error) {
        console.error('获取时间范围数据失败:', error)
        Message.error('获取时间范围数据失败')
      } finally {
        this.loading = false
      }
    },
    handleMarqueeAnimation() {
      const marqueeList = document.querySelector('.marquee-list')
      if (!marqueeList || this.merchantNews.length === 0) return

      const listWidth = marqueeList.scrollWidth
      const containerWidth = marqueeList.parentElement.offsetWidth

      if (this.marqueeOffset >= listWidth) {
        this.marqueeOffset = 0
      } else {
        this.marqueeOffset += 1
      }

      // 当所有内容都滚动完后，重置位置
      if (this.marqueeOffset >= listWidth - containerWidth) {
        setTimeout(() => {
          this.marqueeOffset = 0
        }, 500)
      }
    },
    async updateMerchantNews() {
      try {
        const data = await getMerchantNews()
        this.merchantNews = data
      } catch (error) {
        console.error('获取商家数据失败:', error)
      }
    },
    initChart(chartDom, type) {
      if (!chartDom) return;
      
      // 初始化图表实例
      const chart = echarts.init(chartDom);
      
      // 根据类型配置不同的图表选项
      let option = {};
      
      switch(type) {
        case 'trade':
          option = {
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                type: 'shadow'
              }
            },
            grid: {
              left: '3%',
              right: '4%',
              bottom: '3%',
              containLabel: true
            },
            xAxis: [{
              type: 'category',
              data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
              axisLabel: {
                color: '#fff'
              }
            }],
            yAxis: [{
              type: 'value',
              axisLabel: {
                color: '#fff'
              }
            }],
            series: [{
              name: '交易额',
              type: 'bar',
              barWidth: '60%',
              data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              itemStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  { offset: 0, color: '#00f2f1' },
                  { offset: 1, color: '#0082fc' }
                ])
              }
            }]
          };
          break;
          
        case 'member':
          option = {
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                type: 'shadow'
              }
            },
            grid: {
              left: '3%',
              right: '4%',
              bottom: '3%',
              containLabel: true
            },
            xAxis: [{
              type: 'category',
              data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
              axisLabel: {
                color: '#fff'
              }
            }],
            yAxis: [{
              type: 'value',
              axisLabel: {
                color: '#fff'
              }
            }],
            series: [{
              name: '会员数',
              type: 'line',
              smooth: true,
              data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              itemStyle: {
                color: '#ffc000'
              },
              lineStyle: {
                color: '#ffc000',
                width: 3
              },
              areaStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  { offset: 0, color: 'rgba(255, 192, 0, 0.5)' },
                  { offset: 1, color: 'rgba(255, 192, 0, 0.1)' }
                ])
              }
            }]
          };
          break;
          
        case 'good':
          option = {
            tooltip: {
              trigger: 'item',
              formatter: '{a} <br/>{b}: {c} ({d}%)'
            },
            legend: {
              orient: 'vertical',
              right: 10,
              top: 'center',
              data: ['食品', '家电', '服装', '日用品', '其他'],
              textStyle: {
                color: '#fff'
              }
            },
            series: [{
              name: '商品种类',
              type: 'pie',
              radius: ['40%', '70%'],
              avoidLabelOverlap: false,
              itemStyle: {
                borderRadius: 10,
                borderColor: '#040d4a',
                borderWidth: 2
              },
              label: {
                show: false
              },
              emphasis: {
                label: {
                  show: true,
                  fontSize: '12',
                  fontWeight: 'bold'
                }
              },
              labelLine: {
                show: false
              },
              data: [
                { value: 0, name: '食品' },
                { value: 0, name: '家电' },
                { value: 0, name: '服装' },
                { value: 0, name: '日用品' },
                { value: 0, name: '其他' }
              ]
            }]
          };
          break;
          
        case 'order':
          option = {
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                type: 'shadow'
              }
            },
            grid: {
              left: '3%',
              right: '4%',
              bottom: '3%',
              containLabel: true
            },
            xAxis: [{
              type: 'category',
              data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
              axisLabel: {
                color: '#fff'
              }
            }],
            yAxis: [{
              type: 'value',
              axisLabel: {
                color: '#fff'
              }
            }],
            series: [{
              name: '订单数',
              type: 'bar',
              barWidth: '60%',
              data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              itemStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                  { offset: 0, color: '#67c23a' },
                  { offset: 1, color: '#165824' }
                ])
              }
            }]
          };
          break;
          
        case 'coupon':
          option = {
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                type: 'shadow'
              }
            },
            grid: {
              left: '3%',
              right: '4%',
              bottom: '3%',
              containLabel: true
            },
            xAxis: [{
              type: 'category',
              data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
              axisLabel: {
                color: '#fff'
              }
            }],
            yAxis: [{
              type: 'value',
              axisLabel: {
                color: '#fff'
              }
            }],
            series: [{
              name: '优惠券使用数',
              type: 'line',
              smooth: true,
              data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              itemStyle: {
                color: '#f56c6c'
              },
              lineStyle: {
                color: '#f56c6c',
                width: 3
              }
            }]
          };
          break;
          
        case 'merchant_penetration':
          option = {
            tooltip: {
              trigger: 'item',
              formatter: '{a} <br/>{b}: {c}%'
            },
            visualMap: {
              show: false,
              min: 0,
              max: 100,
              inRange: {
                colorLightness: [0.2, 1]
              }
            },
            series: [{
              name: '商家渗透率',
              type: 'pie',
              radius: '70%',
              center: ['50%', '50%'],
              roseType: 'radius',
              itemStyle: {
                borderRadius: 5,
                color: '#2d8cf0',
                borderColor: '#040d4a',
                borderWidth: 2
              },
              label: {
                color: '#fff'
              },
              data: [
                { value: 0, name: '北京' },
                { value: 0, name: '上海' },
                { value: 0, name: '广州' },
                { value: 0, name: '深圳' },
                { value: 0, name: '杭州' }
              ]
            }]
          };
          break;
          
        case 'user_penetration':
          option = {
            tooltip: {
              trigger: 'item',
              formatter: '{a} <br/>{b}: {c}%'
            },
            visualMap: {
              show: false,
              min: 0,
              max: 100,
              inRange: {
                colorLightness: [0.2, 1]
              }
            },
            series: [{
              name: '用户渗透率',
              type: 'pie',
              radius: '70%',
              center: ['50%', '50%'],
              roseType: 'radius',
              itemStyle: {
                borderRadius: 5,
                color: '#67c23a',
                borderColor: '#040d4a',
                borderWidth: 2
              },
              label: {
                color: '#fff'
              },
              data: [
                { value: 0, name: '北京' },
                { value: 0, name: '上海' },
                { value: 0, name: '广州' },
                { value: 0, name: '深圳' },
                { value: 0, name: '杭州' }
              ]
            }]
          };
          break;
          
        case 'merchant_ranking':
          option = {
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                type: 'shadow'
              }
            },
            grid: {
              left: '3%',
              right: '4%',
              bottom: '3%',
              containLabel: true
            },
            xAxis: {
              type: 'value',
              axisLabel: {
                color: '#fff'
              }
            },
            yAxis: {
              type: 'category',
              data: ['商家1', '商家2', '商家3', '商家4', '商家5'],
              axisLabel: {
                color: '#fff'
              }
            },
            series: [{
              name: '收益',
              type: 'bar',
              data: [0, 0, 0, 0, 0],
              itemStyle: {
                color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
                  { offset: 0, color: '#83bff6' },
                  { offset: 0.5, color: '#188df0' },
                  { offset: 1, color: '#188df0' }
                ])
              }
            }]
          };
          break;
          
        case 'consumer_ranking':
          option = {
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                type: 'shadow'
              }
            },
            grid: {
              left: '3%',
              right: '4%',
              bottom: '3%',
              containLabel: true
            },
            xAxis: {
              type: 'value',
              axisLabel: {
                color: '#fff'
              }
            },
            yAxis: {
              type: 'category',
              data: ['用户1', '用户2', '用户3', '用户4', '用户5'],
              axisLabel: {
                color: '#fff'
              }
            },
            series: [{
              name: '提现额',
              type: 'bar',
              data: [0, 0, 0, 0, 0],
              itemStyle: {
                color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
                  { offset: 0, color: '#ffb980' },
                  { offset: 0.5, color: '#ff7b2e' },
                  { offset: 1, color: '#ff7b2e' }
                ])
              }
            }]
          };
          break;
      }
      
      // 设置图表选项
      chart.setOption(option);
      
      // 保存图表实例，便于后续更新
      this[`${type}Chart`] = chart;
      
      return chart;
    },
    
    updateChartData(chartDom, type, data) {
      if (!chartDom || !data) {
        console.warn(`无法更新${type}图表:`, !chartDom ? 'DOM元素不存在' : '数据为空');
        return;
      }
      
      try {
        // 获取图表实例，如果没有则初始化
        let chart = this[`${type}Chart`];
        if (!chart) {
          chart = this.initChart(chartDom, type);
          if (!chart) {
            console.error(`初始化${type}图表失败`);
            return;
          }
        }
        
        // 根据类型和数据更新图表
        if (chart) {
          let option = {};
          
          switch(type) {
            case 'trade':
              if (!Array.isArray(data.values)) {
                console.error('交易数据格式错误:', data);
                return;
              }
              option = {
                series: [{
                  data: data.values
                }]
              };
              break;
              
            case 'member':
              if (!Array.isArray(data.values)) {
                console.error('会员数据格式错误:', data);
                return;
              }
              option = {
                series: [{
                  data: data.values
                }]
              };
              break;
              
            case 'good':
              if (!Array.isArray(data.categories)) {
                console.error('商品数据格式错误:', data);
                return;
              }
              option = {
                series: [{
                  data: data.categories
                }]
              };
              break;
              
            case 'order':
              if (!Array.isArray(data.values)) {
                console.error('订单数据格式错误:', data);
                return;
              }
              option = {
                series: [{
                  data: data.values
                }]
              };
              break;
              
            case 'coupon':
              if (!Array.isArray(data.values)) {
                console.error('优惠券数据格式错误:', data);
                return;
              }
              option = {
                series: [{
                  data: data.values
                }]
              };
              break;
              
            case 'merchant_penetration':
              if (!Array.isArray(data.regions)) {
                console.error('商家渗透率数据格式错误:', data);
                return;
              }
              option = {
                series: [{
                  data: data.regions
                }]
              };
              break;
              
            case 'user_penetration':
              if (!Array.isArray(data.regions)) {
                console.error('用户渗透率数据格式错误:', data);
                return;
              }
              option = {
                series: [{
                  data: data.regions
                }]
              };
              break;
              
            case 'merchant_ranking':
              if (!Array.isArray(data.names) || !Array.isArray(data.values)) {
                console.error('商家排行数据格式错误:', data);
                return;
              }
              option = {
                yAxis: {
                  data: data.names || []
                },
                series: [{
                  data: data.values || []
                }]
              };
              break;
              
            case 'consumer_ranking':
              if (!Array.isArray(data.names) || !Array.isArray(data.values)) {
                console.error('消费者排行数据格式错误:', data);
                return;
              }
              option = {
                yAxis: {
                  data: data.names || []
                },
                series: [{
                  data: data.values || []
                }]
              };
              break;
            
            default:
              console.warn(`未知的图表类型: ${type}`);
              return; // 如果类型不匹配，直接返回
          }
          
          chart.setOption(option);
        }
      } catch (error) {
        console.error(`更新${type}图表时出错:`, error);
      }
    },
    
    resizeCharts() {
      // 响应窗口大小变化，调整所有图表大小
      const charts = [
        this.tradeChart,
        this.memberChart,
        this.goodChart,
        this.orderChart,
        this.couponChart,
        this.merchant_penetrationChart,
        this.user_penetrationChart,
        this.merchant_rankingChart,
        this.consumer_rankingChart
      ];
      
      charts.forEach(chart => {
        if (chart) {
          chart.resize();
        }
      });
    },
    
    destroyCharts() {
      // 销毁所有图表实例，释放资源
      const charts = [
        this.tradeChart,
        this.memberChart,
        this.goodChart,
        this.orderChart,
        this.couponChart,
        this.merchant_penetrationChart,
        this.user_penetrationChart,
        this.merchant_rankingChart,
        this.consumer_rankingChart
      ];
      
      charts.forEach(chart => {
        if (chart) {
          chart.dispose();
        }
      });
    },
    
    // 修改websocketService订阅方法，增加错误处理和重连机制
    subscribeToAll() {
      try {
        // 添加重连逻辑
        const connectWebSocket = () => {
          try {
            websocketService.connect();
            console.log('WebSocket连接成功');
            
            // 订阅各种数据更新，添加错误处理
            const subscribeWithErrorHandling = (topic, callback) => {
              try {
                websocketService.subscribe(topic, (data) => {
                  try {
                    callback(data);
                  } catch (error) {
                    console.error(`处理${topic}数据时出错:`, error);
                    this.error = `处理${topic}数据时出错，部分图表可能不会更新`;
                  }
                });
              } catch (error) {
                console.error(`订阅${topic}失败:`, error);
              }
            };
            
            // 使用增强的订阅方法
            subscribeWithErrorHandling('trade', (data) => {
              if (data && this.$refs.echart1) {
                this.updateChartData(this.$refs.echart1, 'trade', data);
              }
            });
            
            subscribeWithErrorHandling('member', (data) => {
              if (data && this.$refs.echart2) {
                this.updateChartData(this.$refs.echart2, 'member', data);
              }
            });
            
            subscribeWithErrorHandling('good', (data) => {
              if (data && this.$refs.echart4) {
                this.updateChartData(this.$refs.echart4, 'good', data);
              }
            });
            
            subscribeWithErrorHandling('order', (data) => {
              if (data && this.$refs.echart5) {
                this.updateChartData(this.$refs.echart5, 'order', data);
              }
            });
            
            subscribeWithErrorHandling('coupon', (data) => {
              if (data && this.$refs.echart6) {
                this.updateChartData(this.$refs.echart6, 'coupon', data);
              }
            });
            
            // 订阅快捷统计数据更新
            subscribeWithErrorHandling('quickStats', (data) => {
              if (!data) return;
              
              if (this.$refs.fb1) this.$refs.fb1.innerHTML = `<span>今日订单：${data.orderCount || 0}</span>`;
              if (this.$refs.fb2) this.$refs.fb2.innerHTML = `<span>今日会员：${data.memberCount || 0}</span>`;
              if (this.$refs.fb3) this.$refs.fb3.innerHTML = `<span>今日商品：${data.goodCount || 0}</span>`;
            });
            
            // 订阅商家地区渗透率数据更新
            subscribeWithErrorHandling('merchantPenetration', (data) => {
              if (data && this.$refs.echart7) {
                this.updateChartData(this.$refs.echart7, 'merchant_penetration', data);
              }
            });
            
            // 订阅用户地区渗透率数据更新
            subscribeWithErrorHandling('userPenetration', (data) => {
              if (data && this.$refs.echart8) {
                this.updateChartData(this.$refs.echart8, 'user_penetration', data);
              }
            });
            
            // 订阅商家收益排行数据更新
            subscribeWithErrorHandling('merchantRanking', (data) => {
              if (data && this.$refs.echart9) {
                this.updateChartData(this.$refs.echart9, 'merchant_ranking', data);
              }
            });
            
            // 订阅消费者提现排行数据更新
            subscribeWithErrorHandling('consumerRanking', (data) => {
              if (data && this.$refs.echart10) {
                this.updateChartData(this.$refs.echart10, 'consumer_ranking', data);
              }
            });
            
            // 订阅商家入驻通知
            subscribeWithErrorHandling('merchantNews', (data) => {
              if (data) {
                this.merchantNews = data;
              }
            });
            
            console.log('已成功订阅所有WebSocket数据流');
            
            // 添加连接断开事件监听
            websocketService.onDisconnect(() => {
              console.warn('WebSocket连接已断开，尝试重新连接...');
              setTimeout(() => {
                connectWebSocket();
              }, 5000); // 5秒后重试
            });
            
          } catch (error) {
            console.error('WebSocket连接失败:', error);
            this.error = 'WebSocket连接失败，5秒后将重试连接';
            // 如果连接失败，5秒后重试
            setTimeout(() => {
              connectWebSocket();
            }, 5000);
          }
        };
        
        // 初始连接
        connectWebSocket();
      } catch (error) {
        console.error('WebSocket初始化失败:', error);
        this.error = 'WebSocket初始化失败，部分数据可能无法实时更新';
      }
    },
    
    // 添加 initCharts 方法
    initCharts() {
      // 初始化各个图表
      if (this.$refs.echart1) this.initChart(this.$refs.echart1, 'trade')
      if (this.$refs.echart2) this.initChart(this.$refs.echart2, 'member')
      if (this.$refs.map1) {
        const mapChart = echarts.init(this.$refs.map1)
        const option = {
          tooltip: {
            trigger: 'item',
            formatter: (params) => {
              if (!params.data) return null
              return `
                <div class="map-tooltip">
                  <div class="tooltip-title">${params.name}</div>
                  <div class="tooltip-item">
                    <span>商家数量：</span>
                    <span class="value">${params.data.merchantCount || 0}</span>
                  </div>
                  <div class="tooltip-item">
                    <span>用户数量：</span>
                    <span class="value">${params.data.userCount || 0}</span>
                  </div>
                  <div class="tooltip-item">
                    <span>交易额：</span>
                    <span class="value">¥${params.data.tradeAmount || 0}</span>
                  </div>
                  <div class="tooltip-item">
                    <span>订单数：</span>
                    <span class="value">${params.data.orderCount || 0}</span>
                  </div>
                  <div class="tooltip-item">
                    <span>商家渗透率：</span>
                    <span class="value">${params.data.merchantPenetration || 0}%</span>
                  </div>
                  <div class="tooltip-item">
                    <span>用户渗透率：</span>
                    <span class="value">${params.data.userPenetration || 0}%</span>
                  </div>
                </div>
              `
            }
          },
          geo: {
            map: 'china',
            roam: true, // 开启缩放和平移
            scaleLimit: {
              min: 1,
              max: 5
            },
            zoom: 1.2,
            label: {
              show: true,
              color: '#fff',
              fontSize: 10
            },
            itemStyle: {
              areaColor: 'rgba(0, 242, 241, 0.1)',
              borderColor: '#00f2f1',
              borderWidth: 1
            },
            emphasis: {
              itemStyle: {
                areaColor: 'rgba(0, 242, 241, 0.3)'
              },
              label: {
                color: '#fff',
                fontSize: 12,
                fontWeight: 'bold'
              }
            }
          },
          series: []
        }
        mapChart.setOption(option)
        
        // 监听地图点击事件
        mapChart.on('click', async (params) => {
          if (!params.data) return
          await this.handleRegionSelect({ region: params.name })
        })

        // 监听地图缩放事件
        mapChart.on('georoam', () => {
          const option = mapChart.getOption()
          const zoom = option.geo[0].zoom
          // 根据缩放级别调整标签大小
          option.geo[0].label.fontSize = Math.max(10, Math.min(14, 10 * zoom))
          mapChart.setOption(option)
        })
      }
      if (this.$refs.echart4) this.initChart(this.$refs.echart4, 'good')
      if (this.$refs.echart5) this.initChart(this.$refs.echart5, 'order')
      if (this.$refs.echart6) this.initChart(this.$refs.echart6, 'coupon')

      // 初始化新增图表
      if (this.$refs.echart7) this.initChart(this.$refs.echart7, 'merchant_penetration')
      if (this.$refs.echart8) this.initChart(this.$refs.echart8, 'user_penetration')
      if (this.$refs.echart9) this.initChart(this.$refs.echart9, 'merchant_ranking')
      if (this.$refs.echart10) this.initChart(this.$refs.echart10, 'consumer_ranking')

      // 立即获取一次数据
      this.fetchData()
    },
    async fetchDataByType(type, param, signal) {
      try {
        switch(type) {
          case 'trade':
            return await getTradeStatistics(param, signal);
          case 'member':
            return await getMemberStatistics(param, signal);
          case 'good':
            return await getGoodStatistics(param, signal);
          case 'order':
            return await getOrderStatistics(param, signal);
          case 'coupon':
            return await getCouponStatistics(param, signal);
          case 'quickStats':
            return await getQuickStatistics(signal);
          case 'merchantPenetration':
            return await getMerchantPenetrationStatistics(signal);
          case 'userPenetration':
            return await getUserPenetrationStatistics(signal);
          case 'merchantRanking':
            return await getMerchantRankingStatistics(signal);
          case 'consumerRanking':
            return await getConsumerRankingStatistics(signal);
          case 'merchantNews':
            return await getMerchantNews(signal);
          case 'incomeExpense':
            return await getIncomeExpenseStatistics(signal);
          default:
            console.warn(`未知的数据类型: ${type}`);
            return null;
        }
      } catch (error) {
        console.error(`获取${type}数据失败:`, error);
        throw error;
      }
    },
  },
  mounted() {
    // 启动时间更新
    this.timer = setInterval(this.updateTime, 1000)
    
    // 初始化图表
    this.initCharts()

    // 获取商家数据并启动跑马灯
    this.updateMerchantNews()
    this.marqueeTimer = setInterval(this.handleMarqueeAnimation, 50)

    // 每5分钟更新一次数据
    this.dataTimer = setInterval(() => {
      this.fetchData()
      this.updateMerchantNews()
    }, 5 * 60 * 1000)

    // 每30秒预加载一次数据
    this.preloadTimer = setInterval(this.handlePreload, 30 * 1000)

    // 添加窗口大小改变事件监听
    window.addEventListener('resize', this.resizeCharts)
    
    // 添加全屏变化事件监听
    document.addEventListener('fullscreenchange', this.handleFullscreenChange);
    document.addEventListener('webkitfullscreenchange', this.handleFullscreenChange);
    document.addEventListener('mozfullscreenchange', this.handleFullscreenChange);
    document.addEventListener('MSFullscreenChange', this.handleFullscreenChange);

    // 订阅WebSocket数据
    this.subscribeToAll()
  },
  beforeDestroy() {
    if (this.timer) {
      clearInterval(this.timer)
    }
    if (this.dataTimer) {
      clearInterval(this.dataTimer)
    }
    if (this.preloadTimer) {
      clearInterval(this.preloadTimer)
    }
    if (this.marqueeTimer) {
      clearInterval(this.marqueeTimer)
    }
    // 移除事件监听
    window.removeEventListener('resize', this.resizeCharts)
    
    // 移除全屏变化事件监听
    document.removeEventListener('fullscreenchange', this.handleFullscreenChange);
    document.removeEventListener('webkitfullscreenchange', this.handleFullscreenChange);
    document.removeEventListener('mozfullscreenchange', this.handleFullscreenChange);
    document.removeEventListener('MSFullscreenChange', this.handleFullscreenChange);
    
    // 销毁图表实例
    this.destroyCharts()

    // 断开WebSocket连接
    websocketService.disconnect()
  }
}
</script>

<style scoped>
.data-visualization {
  width: 100%;
  height: 100%;
  background: #000d4a url(../../../assets/background.jpg) center top;
  background-size: cover;
  color: #fff;
  overflow: hidden;
}

.head {
  height: 1.05rem;
  background: url(../../../assets/ft_bg.png) no-repeat center center;
  background-size: 100% 100%;
  position: relative;
  z-index: 100;
}

.head h1 {
  color: #fff;
  text-align: center;
  font-size: 0.4rem;
  line-height: 0.8rem;
}

.weather {
  position: absolute;
  right: 0.3rem;
  top: 0;
  line-height: 0.75rem;
  display: flex;
  align-items: center;
  gap: 1rem;
}

.mainbox {
  padding: 0.1rem 0.1rem 0rem 0.1rem;
}

.mainbox>ul {
  margin-left: -0.1rem;
  margin-right: -0.1rem;
}

.mainbox>ul>li {
  float: left;
  padding: 0 0.1rem;
  width: 33.333333%;
}

.boxall {
  border: 1px solid rgba(25,186,139,.17);
  padding: 0 0.15rem 0.15rem 0.15rem;
  background: rgba(255,255,255,0.04) url(../../../assets/ft_bg.png);
  background-size: 100% auto;
  position: relative;
  margin-bottom: 0.15rem;
  z-index: 10;
}

.alltitle {
  font-size: 0.2rem;
  color: #fff;
  text-align: center;
  line-height: 0.5rem;
}

.boxfoot {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 0.1rem;
  background: url(../../../assets/ft_bg.png) no-repeat center center;
  background-size: 100% 100%;
}

.sy {
  width: 100%;
  height: 33.33%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 0.2rem;
  position: relative;
}

.sy::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(255,255,255,0.1);
  border-radius: 0.1rem;
}

.sy span {
  position: relative;
  z-index: 1;
}

.bar {
  height: 3.2rem;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(25,186,139,.17);
  margin-bottom: 0.15rem;
}

.barbox {
  height: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.barbox ul {
  display: flex;
  width: 100%;
  justify-content: space-around;
}

.barbox ul li {
  font-size: 0.3rem;
  color: #fff;
  text-align: center;
}

.barbox2 {
  height: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.barbox2 ul {
  display: flex;
  width: 100%;
  justify-content: space-around;
}

.barbox2 ul li {
  font-size: 0.2rem;
  color: #fff;
  text-align: center;
}

.map {
  height: 3.2rem;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(25,186,139,.17);
}

.map4 {
  width: 100%;
  height: 100%;
}

.counter {
  font-size: 0.3rem;
  color: #00f2f1;
  font-weight: bold;
}

.refresh-btn {
  margin-left: 1rem;
}

.error-alert {
  margin-bottom: 1rem;
}

.loading-mask {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}

.loading-mask .el-icon-loading {
  font-size: 2rem;
  color: #fff;
}

.allnav {
  position: relative;
  height: calc(100% - 0.5rem);
}

/* 添加选中地区的样式 */
.selected-region {
  position: absolute;
  top: 0.1rem;
  right: 0.1rem;
  background: rgba(47, 137, 207, 0.3);
  padding: 0.1rem 0.2rem;
  border-radius: 0.1rem;
  font-size: 0.2rem;
  color: #fff;
  z-index: 100;
}

/* 预加载进度样式 */
.preload-progress {
  margin-bottom: 1rem;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 0.1rem;
  padding: 0.5rem;
}

.progress-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.5rem;
}

.progress-title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: #fff;
  font-size: 0.2rem;
}

.progress-info {
  display: flex;
  justify-content: space-between;
  margin-bottom: 0.5rem;
  color: #fff;
  font-size: 0.2rem;
}

.progress-bar {
  margin: 0;
}

.progress-bar >>> .el-progress-bar__outer {
  background-color: rgba(255, 255, 255, 0.1);
}

.progress-bar >>> .el-progress-bar__inner {
  background-color: #00f2f1;
  transition: width 0.3s ease;
}

.progress-bar >>> .el-progress-bar__inner.is-exception {
  background-color: #ff9f7f;
}

.progress-details {
  margin-top: 0.5rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: #fff;
  font-size: 0.2rem;
}

.current-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.item-name {
  color: #00f2f1;
}

.item-status {
  padding: 0.1rem 0.3rem;
  border-radius: 0.1rem;
  font-size: 0.18rem;
}

.item-status.loading {
  background-color: rgba(0, 242, 241, 0.2);
  color: #00f2f1;
}

.item-status.success {
  background-color: rgba(103, 194, 58, 0.2);
  color: #67c23a;
}

.item-status.error {
  background-color: rgba(245, 108, 108, 0.2);
  color: #f56c6c;
}

/* 跑马灯样式 */
.marquee-container {
  height: 0.6rem;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(25,186,139,.17);
  margin: 0.1rem;
  display: flex;
  align-items: center;
  overflow: hidden;
  position: relative;
}

.marquee-icon {
  width: 0.8rem;
  height: 100%;
  background: rgba(0,242,241,0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.marquee-icon i {
  font-size: 0.3rem;
  color: #00f2f1;
}

.marquee-content {
  flex: 1;
  overflow: hidden;
  padding: 0 0.2rem;
}

.marquee-list {
  display: flex;
  transition: transform 0.5s linear;
  white-space: nowrap;
}

.marquee-list li {
  display: inline-flex;
  align-items: center;
  margin-right: 2rem;
  font-size: 0.18rem;
}

.merchant-name {
  color: #00f2f1;
  margin-right: 0.5rem;
}

.merchant-time {
  color: #fff;
  margin-right: 0.5rem;
}

.merchant-location {
  color: #ffd04b;
}

/* 地图提示框样式 */
:deep(.map-tooltip) {
  background: rgba(0, 13, 74, 0.9);
  border: 1px solid rgba(0, 242, 241, 0.3);
  padding: 0.2rem;
  border-radius: 0.1rem;
  font-size: 0.14rem;
  color: #fff;
  min-width: 2.5rem;
}

:deep(.tooltip-title) {
  font-size: 0.16rem;
  color: #00f2f1;
  margin-bottom: 0.1rem;
  font-weight: bold;
  border-bottom: 1px solid rgba(0, 242, 241, 0.3);
  padding-bottom: 0.1rem;
}

:deep(.tooltip-item) {
  display: flex;
  justify-content: space-between;
  margin: 0.08rem 0;
  line-height: 1.5;
}

:deep(.tooltip-item .value) {
  color: #ffd04b;
  font-weight: bold;
}

.extra-wrapper {
  position: absolute;
  top: 0.1rem;
  right: 0.2rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  z-index: 100;
}

/* 日期选择器样式 */
:deep(.ant-radio-button-wrapper) {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(0, 242, 241, 0.3);
  color: #fff;
}

:deep(.ant-radio-button-wrapper:hover) {
  background: rgba(0, 242, 241, 0.2);
  color: #00f2f1;
}

:deep(.ant-radio-button-wrapper-checked) {
  background: rgba(0, 242, 241, 0.3);
  border-color: #00f2f1;
  color: #00f2f1;
}

:deep(.ant-calendar-picker) {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 4px;
}

:deep(.ant-calendar-picker-input) {
  background: transparent;
  border-color: rgba(0, 242, 241, 0.3);
  color: #fff;
}

:deep(.ant-calendar-picker-icon) {
  color: rgba(255, 255, 255, 0.7);
}

:deep(.ant-calendar-picker:hover .ant-calendar-picker-input) {
  border-color: #00f2f1;
}

:deep(.ant-calendar) {
  background: rgba(0, 13, 74, 0.95);
  border-color: rgba(0, 242, 241, 0.3);
}

:deep(.ant-calendar-header) {
  border-bottom: 1px solid rgba(0, 242, 241, 0.3);
}

:deep(.ant-calendar-header a) {
  color: #fff;
}

:deep(.ant-calendar-date) {
  color: #fff;
}

:deep(.ant-calendar-date:hover) {
  background: rgba(0, 242, 241, 0.2);
}

:deep(.ant-calendar-selected-day .ant-calendar-date) {
  background: rgba(0, 242, 241, 0.3);
  border-color: #00f2f1;
}

:deep(.ant-calendar-today .ant-calendar-date) {
  border-color: #00f2f1;
  color: #00f2f1;
}

/* 全屏状态下的特殊样式 */
:fullscreen .data-visualization {
  width: 100vw;
  height: 100vh;
}

:-webkit-full-screen .data-visualization {
  width: 100vw;
  height: 100vh;
}

:-ms-fullscreen .data-visualization {
  width: 100vw;
  height: 100vh;
}

/* 添加全屏按钮样式 */
.fullscreen-btn {
  margin-left: 0.5rem;
}

.fullscreen-btn i {
  margin-right: 5px;
}
</style> 